package com.excesys.exsecs.scada.service.impl;



import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.excesys.exsecs.access.constant.RedisConstant;
import com.excesys.exsecs.access.entity.AccessDeviceInfo;
import com.excesys.exsecs.access.entity.AccessProduct;
import com.excesys.exsecs.access.mapper.AccessDeviceInfoMapper;
import com.excesys.exsecs.access.mapper.AccessProductMapper;
import com.excesys.exsecs.access.service.AccessDeviceInfoService;
import com.excesys.exsecs.common.file.core.FileProperties;
import com.excesys.exsecs.scada.entity.ScadaDevice;
import com.excesys.exsecs.scada.entity.ScadaEntity;
import com.excesys.exsecs.scada.entity.ScadaProperty;
import com.excesys.exsecs.scada.entity.ScadaSystemBind;
import com.excesys.exsecs.scada.mapper.ScadaDeviceMapper;
import com.excesys.exsecs.scada.mapper.ScadaSystemBindMapper;
import com.excesys.exsecs.scada.properties.PathProperties;
import com.excesys.exsecs.scada.service.ScadaDeviceService;
import com.excesys.exsecs.scada.service.ScadaPropertyService;
import com.excesys.exsecs.scada.util.JsonProcess;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 组态、设备关联表
 *
 * @author lxc
 * @date 2024-05-17 11:58:34
 */
@Service
@RequiredArgsConstructor
public class ScadaDeviceServiceImpl extends ServiceImpl<ScadaDeviceMapper, ScadaDevice> implements ScadaDeviceService {
	private final AccessDeviceInfoMapper accessDeviceInfoMapper;
	private final AccessProductMapper accessProductMapper;
	private final ScadaDeviceMapper scadaDeviceMapper;
	private final AccessDeviceInfoService accessDeviceInfoService;
	private final StringRedisTemplate redisTemplate;

	private final ScadaPropertyService scadaPropertyService;
	private final FileProperties fileProperties;
	private final JsonProcess jsonProcess;
	private final ScadaEntity scadaEntity;

	private final ScadaSystemBindMapper systemBindMapper;

	@Override
	public Page<AccessDeviceInfo> queryByScadaId(ScadaProperty scadaProperty,AccessDeviceInfo accessDeviceInfo,Page page) {
		//查找该组态下绑定的设备id
		List<ScadaDevice> scadaDevices = scadaDeviceMapper.selectList(Wrappers.<ScadaDevice>lambdaQuery()
				.select(ScadaDevice::getDeviceId)
				.eq(ScadaDevice::getScadaId, scadaProperty.getId()));
		List<Object> collect = scadaDevices.stream().map(mp -> mp.getDeviceId()).collect(Collectors.toList());
		if(ObjectUtils.isEmpty(collect)||collect.size()<=0){
			return null;
		}
		//返回设备列表
		Page<AccessDeviceInfo> page1 = accessDeviceInfoMapper.selectPage(page,
				Wrappers.<AccessDeviceInfo>lambdaQuery()
						.in(ObjectUtils.isNotEmpty(collect),AccessDeviceInfo::getUnitNo,collect)
						.like(StrUtil.isNotEmpty(accessDeviceInfo.getDeviceName()), AccessDeviceInfo::getDeviceName, accessDeviceInfo.getDeviceName())
						.eq(StrUtil.isNotBlank(accessDeviceInfo.getProductKey()), AccessDeviceInfo::getProductKey, accessDeviceInfo.getProductKey()));
		if(ObjectUtils.isNotEmpty(page1) && CollectionUtils.isNotEmpty(page1.getRecords())){
			page1.getRecords().forEach(it->{
				AccessProduct product = accessProductMapper.
						selectOne(Wrappers.<AccessProduct>lambdaQuery()
								.eq(AccessProduct::getProductKey, it.getProductKey()));
				it.setProductName(product.getName());
				it.setId(scadaProperty.getId());
			});
		}
		return page1;
	}

	@Override
	public Page queryPage(ScadaProperty scadaProperty, AccessDeviceInfo accessDeviceInfo,Page page) {
		//把组态中已经绑定的设备id挑出来 返回未绑定的设备列表
		List<ScadaDevice> scadaDevices = scadaDeviceMapper.selectList(Wrappers.<ScadaDevice>lambdaQuery()
				.select(ScadaDevice::getDeviceId)
				.eq(ScadaDevice::getScadaId, scadaProperty.getId()));
		List<Object> collect = scadaDevices.stream().map(mp -> mp.getDeviceId()).collect(Collectors.toList());

		Page<AccessDeviceInfo> page1 = accessDeviceInfoMapper.selectPage(page,
				Wrappers.<AccessDeviceInfo>lambdaQuery()
						.notIn(ObjectUtils.isNotEmpty(collect),AccessDeviceInfo::getUnitNo,collect)
						.like(StrUtil.isNotEmpty(accessDeviceInfo.getDeviceName()), AccessDeviceInfo::getDeviceName, accessDeviceInfo.getDeviceName())
						.eq(StrUtil.isNotBlank(accessDeviceInfo.getProductKey()), AccessDeviceInfo::getProductKey, accessDeviceInfo.getProductKey()));
		if(ObjectUtils.isNotEmpty(page1) && CollectionUtils.isNotEmpty(page1.getRecords())){
			page1.getRecords().forEach(it->{
				AccessProduct product = accessProductMapper.selectOne(Wrappers.<AccessProduct>lambdaQuery()
								.eq(AccessProduct::getProductKey, it.getProductKey()));
				it.setProductName(product.getName());
			});
		}
		return page1;
	}

	@Override
	public boolean saveScadaDevice(ScadaDevice scadaDevice) {
		//通过设备ID获取通道
		if(ObjectUtil.isNotEmpty(scadaDevice) && CollectionUtils.isNotEmpty(scadaDevice.getDeviceIds())){
			List<ScadaDevice> scadaDeviceList = new ArrayList<>();
			scadaDevice.getDeviceIds().forEach(item -> {
				ScadaDevice sd = new ScadaDevice();
				Object[] properties = null;
				List<JSONObject> deviceProperties = accessDeviceInfoService.detail(item).getProperties();
				if(ObjectUtils.isNotEmpty(deviceProperties) && deviceProperties.size() > 0){
					properties = deviceProperties.stream()
							.map(mp -> mp.set("flag",1)).toArray();
				}
				sd.setScadaId(scadaDevice.getScadaId());
				sd.setDeviceId(item);
				Map<String,Object> map = new HashMap<>();
				map.put("properties",properties);
				sd.setDeviceModel(new JSONObject(map));
				scadaDeviceList.add(sd);
			});
			this.saveBatch(scadaDeviceList);
			// TODO 调用方法修改JSON文件
			//通过组态id查找fileName
			String zipfileName = scadaPropertyService.getById(scadaDevice.getScadaId()).getFileName();
			String[] split = zipfileName.split("\\.");
			String path = scadaEntity.getBasePath() + FileUtil.FILE_SEPARATOR + "package"
					+ FileUtil.FILE_SEPARATOR + split[0] + PathProperties.SUFFIX
					+PathProperties.JSON;
			log.error("path : "+path);
			//jsonProcess.ChangeHttp(path,scadaDevice.getScadaId().toString());
		}
		return false;
	}

	@Override
	public boolean removeBatchByDeviceIds(ScadaDevice scadaDevice) {
		if(ObjectUtil.isNotEmpty(scadaDevice) && CollectionUtils.isNotEmpty(scadaDevice.getDeviceIds())){
			scadaDevice.getDeviceIds().forEach(item -> {
				Map map = new HashMap<>();
				map.put("scada_id",scadaDevice.getScadaId());
				map.put("device_id",item);
				this.scadaDeviceMapper.deleteByMap(map);
			});
			return true;
		}
		return false;
	}

	@Override
	public JSONObject test(ScadaDevice scadaDevice) {
		//通过设备ID获取通道
		Map<String,Object> map = new HashMap<>();
		if(ObjectUtil.isNotEmpty(scadaDevice) && CollectionUtils.isNotEmpty(scadaDevice.getDeviceIds())){
			scadaDevice.getDeviceIds().forEach(item -> {
				Object[] objects = accessDeviceInfoService.detail(item).getProperties().toArray();
				map.put(item,objects);
			});
		}
		return new JSONObject(map);
	}

	@Override
	public List<JSONObject> queryModel(ScadaDevice scadaDevice) {
		List<JSONObject> jsonObjects = new ArrayList<>();
		if(ObjectUtils.isNotEmpty(scadaDevice.getScadaId()) && StringUtils.isNotEmpty(scadaDevice.getDeviceId())){
			List<ScadaDevice> scadaDevices = baseMapper.selectList(Wrappers.<ScadaDevice>lambdaQuery()
					.select(ScadaDevice::getDeviceModel)
					.eq(ScadaDevice::getScadaId, scadaDevice.getScadaId())
					.eq(ScadaDevice::getDeviceId, scadaDevice.getDeviceId()));
			Object properties = scadaDevices.get(0).getDeviceModel().get("properties");
			for (Map<String, Object> property : (List<Map<String, Object>>) properties) {
				property.put("dataTypeStr",property.get("dataType").toString().replaceAll("\\\"",""));
				jsonObjects.add(new JSONObject(property));
			}
			return jsonObjects;
		}
		return null;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean updateModel(ScadaDevice scadaDevice) {
		if (scadaDevice.getModels().length > 0 && StringUtils.isNotEmpty(scadaDevice.getDeviceId())
			&& ObjectUtils.isNotEmpty(scadaDevice.getScadaId())){

			List<ScadaDevice> scadaDevices = baseMapper.selectList(Wrappers.<ScadaDevice>lambdaQuery()
					.select(ScadaDevice::getDeviceModel)
					.eq(ScadaDevice::getScadaId, scadaDevice.getScadaId())
					.eq(ScadaDevice::getDeviceId, scadaDevice.getDeviceId()));
			Object properties = scadaDevices.get(0).getDeviceModel().get("properties");
			List propertyList = new ArrayList<>();
			Integer[] models = scadaDevice.getModels();
			Integer num = 0;
			for (Map<String, Object> property : (List<Map<String, Object>>) properties) {
				property.put("flag",models[num]);
				num++;
				propertyList.add(new JSONObject(property));
			}
			JSONObject jsonObject = new JSONObject();
			jsonObject.set("properties",propertyList);
			ScadaDevice scadaDevice1 = new ScadaDevice();
			scadaDevice1.setDeviceModel(jsonObject);
			int update = this.baseMapper.update(scadaDevice1, Wrappers.<ScadaDevice>lambdaQuery()
					.eq(ScadaDevice::getScadaId, scadaDevice.getScadaId())
					.eq(ScadaDevice::getDeviceId, scadaDevice.getDeviceId()));
			return update > 0;
		}
		return false;
	}

	@Override
	public List getModelData2() {
		List<Map<String,Object>> mapList = new ArrayList<>();

		Object redisObject = redisTemplate.opsForHash().get(RedisConstant.REPORT_LIST_KEY, "6f8ffa6e97524e43ab27811a8ed3ff87");
		if(ObjectUtils.isNotEmpty(redisObject)){
			JSONObject jsonObject = new JSONObject(redisObject);
			Map map = (Map) jsonObject.get("data");
			Set<Map.Entry<String,Integer>> entries = map.entrySet();
			for(Map.Entry<String,Integer> entry : entries){
				Map<String,Object> objectMap = new HashMap<>();
				String key = jsonObject.get("device_id").toString()+"_"+ entry.getKey();
				objectMap.put("tag",key);
				objectMap.put("text",entry.getValue().toString());
				mapList.add(objectMap);
			}
			return mapList;
		}
		return mapList;
	}

	@Override
	public List getModelData(Long id) {
		//返回格式 [{tag:"",text:"90"},{tag:"",text:""}]
		List<Map<String,Object>> mapList = new ArrayList<>();

		List<ScadaDevice> scadaDeviceList = scadaDeviceMapper
				.selectList(Wrappers.<ScadaDevice>lambdaQuery().eq(ScadaDevice::getScadaId, id));
		scadaDeviceList.stream().map(ScadaDevice::getDeviceId).forEach(devId -> {
			Object redisObject = redisTemplate.opsForHash().get(RedisConstant.REPORT_LIST_KEY, devId);
			if(ObjectUtils.isNotEmpty(redisObject)){
				JSONObject jsonObject = new JSONObject(redisObject);
				//设备在离线
				Map<String,Object> onlineMap = new HashMap<>();
				String tag = jsonObject.get("unit_no").toString()+"_online";
				onlineMap.put("tag",tag);
				onlineMap.put("text",jsonObject.get("online").toString());
				mapList.add(onlineMap);
				//设备通道
				List<ScadaDevice> scadaDevice = baseMapper.selectList(Wrappers.<ScadaDevice>lambdaQuery()
						.select(ScadaDevice::getDeviceModel)
						.eq(ScadaDevice::getScadaId, id)
						.eq(ScadaDevice::getDeviceId, devId));
				if(ObjectUtil.isNotEmpty(scadaDevice) && scadaDevice.size()>0){
					JSONArray jsonArray = JSONArray.parseArray(scadaDevice.get(0).getDeviceModel().get("properties").toString());
					for (int i = 0; i < jsonArray.size(); i++) {
						JSONObject channel = new JSONObject(jsonArray.get(i));
						if(channel.get("flag").toString().equals("1")){
							Map<String,Object> objectMap = new HashMap<>();
							String key = jsonObject.get("unit_no").toString()+"_"+ channel.get("identifier");
							objectMap.put("tag",key);
							JSONObject object = new JSONObject(jsonObject.get("data"));
							objectMap.put("text",object.get(channel.get("identifier")));
							mapList.add(objectMap);
						}
					}
				}
//				Map map = (Map) jsonObject.get("data");
//				Set<Map.Entry<String,Object>> entries = map.entrySet();
//				for(Map.Entry<String,Object> entry : entries){
//					Map<String,Object> objectMap = new HashMap<>();
//					String key = jsonObject.get("unit_no").toString()+"_"+ entry.getKey();
//					objectMap.put("tag",key);
//					objectMap.put("text",entry.getValue().toString());
//					mapList.add(objectMap);
//				}
			}else {
				//数据未上报设定离线
				Map<String,Object> unExist = new HashMap<>();
				unExist.put("tag",devId+"_online");
				unExist.put("text","0");
				mapList.add(unExist);
			}
		});

		//系统参数推送
		List<ScadaSystemBind> bindList = systemBindMapper.selectList(Wrappers.<ScadaSystemBind>lambdaQuery().eq(ScadaSystemBind::getScadaId, id));
		if(ObjectUtil.isNotNull(bindList) && bindList.size()>0){
			List<String> collect = bindList.stream().map(ScadaSystemBind::getUnitNo).collect(Collectors.toList());
			collect.forEach(unitNo->{
				Object obj = redisTemplate.opsForHash().get(RedisConstant.SYSTEM_PROPERTY_LIST, unitNo);
				if(ObjectUtil.isNotNull(obj)){
					JSONObject jsonObject = new JSONObject(obj);
					Map<String,Object> data = (Map<String, Object>) jsonObject.get(RedisConstant.DATA);
					for (Map.Entry<String,Object> entry : data.entrySet()){
						Map<String,Object> sysProp = new HashMap<>();
						sysProp.put("tag",unitNo+"_"+entry.getKey());
						sysProp.put("text",entry.getValue());
						mapList.add(sysProp);
					}
				}
			});
		}
		return mapList;
	}
}